package com.rtsapp.server.benchmark.cases.cmd;

import com.rtsapp.server.benchmark.ITestCase;
import com.rtsapp.server.benchmark.ITestCaseIterator;
import com.rtsapp.server.benchmark.ITestCaseListener;
import com.rtsapp.server.benchmark.runner.ContextUtils;
import com.rtsapp.server.common.ByteBuffer;
import com.rtsapp.server.common.IByteBuffer;
import com.rtsapp.server.network.protocol.command.ICommand;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoopGroup;
import com.rtsapp.server.logger.Logger;

import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 连接执行的handler
 */
public abstract class CommandCaseHandler extends ChannelInboundHandlerAdapter implements ITestCaseListener {


    private static Logger LOGGER =com.rtsapp.server.logger.LoggerFactory.getLogger( CommandCaseHandler.class );


    private ScheduledExecutorService executorService;
    private ITestCaseIterator testCaseGenerator;
    private Map<String,Object> context ;


    private Channel channel;

    /**
     * 当前正在执行的case
     */
    private ITestCase currentCase;


    public CommandCaseHandler( ){

    }

    /**
     * 初始化
     * @param loopGroup
     * @param testCaseGenerator
     * @param context
     */
    public void initialize( EventLoopGroup loopGroup,  ITestCaseIterator testCaseGenerator ,  Map<String,Object> context  ){
        this.executorService = loopGroup;
        this.testCaseGenerator = testCaseGenerator;
        this.context = context;

        this.context.put( "commandHandler", this );
    }


    @Override
    public void onStart(ITestCase testCase) {
        currentCase = testCase;
    }

    @Override
    public void onComplete(ITestCase testCase) {
        if (testCase == currentCase) {
            currentCase = null;
            gotoNext();
        }
    }


    /**
     * 进入到下一个测试用例
     */
    private void gotoNext() {
        if( testCaseGenerator.hasNext() ){
            ITestCase test =  testCaseGenerator.next();

            // 如果测试用例编写错误，这里会报空指针异常, 设计就是不进行捕获，使用者必须先修改完测试用例后再进行测试
            test.addListener( this );
            if( test instanceof ICommandCase ){
                ((ICommandCase)test).setHandler( this );
            }
            scheduleTest(test);

        }else{
            complete();
        }
    }

    private void scheduleTest(ITestCase test) {

        executorService.schedule(new Runnable() {
            @Override
            public void run() {
                test.start();
            }

        }, test.delayTime(), TimeUnit.MILLISECONDS );

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive( ctx );

        this.channel = ctx.channel();

        gotoNext();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        try {
            ByteBuf buf = (ByteBuf) msg;
            int length = buf.readInt();

            ByteBuffer buffer = new ByteBuffer( buf );
            int commandId = buffer.getInt(buffer.readerIndex());

            onReceiveCommand( commandId, buffer );

        } catch (Throwable ex) {
            LOGGER.error(ex, "数据包处理错误");
        }


    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
        LOGGER.error("Command Case Handler出错", cause );
    }

    private void onReceiveCommand( int commandId, IByteBuffer buffer ){
        if( currentCase != null ){
            if( currentCase instanceof ICommandCase){
                ICommandCase test = (ICommandCase)currentCase;

                //如果接收到了期望的消息
                if( test.recieve( commandId, buffer) ){
                    //执行接收到的消息
                    processRecievedCommand( test.getResponse() );
                    //用例继续玩下执行
                    test.continueExecute();
                }

            }
        }
    }


    public void send( ICommand request ){

        processSendCommand( request );


        channel.writeAndFlush( request );

    }


    /**
     * 关闭
     */
    public void complete(){
        LOGGER.debug( "[{}]:一次连接的所有操作都完成, 关闭channel, channel={}", ContextUtils.getContextId(this.context), channel );
        this.channel.close();
    }


    /**
     * 发送消息前，发送的消息头
     * @param buffer
     */
    public abstract void sendPackageHead( IByteBuffer buffer );


    /**
     * 当接收到消息后对接收到的消息进行处理
     * @param command
     */
    public abstract void processRecievedCommand( ICommand command );


    /**
     * 发送消息前对消息进行处理
     * @param command
     */
    public abstract void processSendCommand( ICommand command );

}